#ifndef _IMAGE_H_
#define _IMAGE_H_

#include "BuzzGlobals.h"

// OpenGL RGBA masks
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
    #define SDL_RMASK 0x000000FF
    #define SDL_GMASK 0x0000FF00
    #define SDL_BMASK 0x00FF0000
    #define SDL_AMASK 0xFF000000
#else
	#define SDL_RMASK 0xFF000000
    #define SDL_RMASK 0x00FF0000
    #define SDL_RMASK 0x0000FF00
    #define SDL_RMASK 0x000000FF
#endif

struct ColourKey{
	ColourKey(){ empty = true; }
	ColourKey(byte r, byte g, byte b)
	{
		this->r = r;
		this->g = g;
		this->b = b;

		empty = false;
	}

	byte r, g, b;
	bool empty;
};

/**
 * Image - Wrapper for a single OpenGL texture
 * Also includes methods to draw the texture, as well as rotate, scale, tint
 * and set the alpha values for drawing.
 *
 * Image also has a reference point giving the centre point of the image for
 * drawing. Note that scaling and rotating are still done from the centre point,
 * not the reference point.
 */
class Image {
public:
	Image();
	Image(const char* filename, ColourKey key=ColourKey());

    Image(SDL_Surface* surface, SDL_Rect* rect, ColourKey key=ColourKey());

	virtual ~Image();

	virtual int getWidth();
	virtual int getHeight();

    Uint8 getAlpha(){ return alpha; }
    float getRotation(){ return rotation; }
    float getScale(){ return scale; }


    void setAlpha(Uint8 alpha){ this->alpha = alpha; }
    void setTints(Uint8 r, Uint8 g, Uint8 b){ tintR = r; tintG = g; tintB = b; }
    void setScale(float scale){ this->scale = scale; }
    void setRotation(float rotation){ this->rotation = rotation; }


    /**
     * Sets the reference point of the image. The reference point will be the
     * centre point of a draw
     */
	virtual void setReferencePoint(int x, int y){ refX = x; refY = y; }

	void setRefCentre(){ setReferencePoint(width/2, height/2); }

	void setRefBottomCentre(){ setReferencePoint(width/2, height); }

    /**
     * Draws the image, with the image's reference point at specified
     * coordinates.
     *
     * \param flipped
     * If true, this image will be flipped about the vertical axis
     */
    virtual void draw(int x, int y, bool flipped = false);

	void draw(SDL_Rect* destination, SDL_Rect* source);

	void draw(SDL_Rect* destination, bool flipped, float uLeft, float uRight, float vTop, float vBottom);

    virtual byte** getCollisionMap(){ return collisionMap; }

	virtual bool collisionAt(int x, int y, bool flipped=false);

	int getRefX(){ return refX; }
	int getRefY(){ return refY; }

protected:
    /// OpenGL texture ID for this Image/Texture
	GLuint texID;

	/// Width of the originally loaded image
	int width;

	/// Height of the originally loaded image
	int height;

    /// Actual width of the OpenGL texture (may be larger as must be power of 2)
	int actualWidth;

	/// Actual height of the OpenGL texture (may be larger as must be power of 2)
	int actualHeight;

    /// How much to rotate the image by when drawing (degrees clockwise)
    float rotation;

	float texRefTop, texRefBottom, texRefLeft, texRefRight;

	/// Reference point for drawing
	int refX, refY;

    Uint8 alpha;
    GLubyte tintR, tintG, tintB;
    float scale;

    /**
     * 'Borrowed' function to convert an SDL surface to an OpenGL texture.
     * Modified to:
     *   Allow colour keying
     *   Accept a source rectangle to copy from the image (rather than the whole image)
     *   Set some class instance variables
     */
	GLuint SDL_GL_LoadTexture(SDL_Surface *surface, GLfloat *texcoord, ColourKey* key, SDL_Rect* srcRect);

	/// 2D collision map
	byte** collisionMap;
};

#endif
